import 'package:flutter/material.dart';

class CustomWrapWithTextMeasureDemo extends StatelessWidget {
  const CustomWrapWithTextMeasureDemo({super.key});

  @override
  Widget build(BuildContext context) {
    final tags = [
      'Flutter',
      'Dart',
      'Android',
      'FlowDelegate',
      '自适应宽度',
      'UI布局',
      'Wrap替代',
      '标签',
      '性能更好',
      '高效'
    ];

    return Scaffold(
      appBar: AppBar(title: const Text('Flow 模仿 Wrap（测量文本宽度）')),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Container(
          color: Colors.red,
          child: Flow(
            delegate: _TextWrapFlowDelegate(
              texts: tags,
              style: const TextStyle(fontSize: 16),
              padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
              margin: const EdgeInsets.all(8),
            ),
            children: tags
                .map((text) => Container(
              padding:
              const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
              decoration: BoxDecoration(
                color: Colors.blue.shade200,
                borderRadius: BorderRadius.circular(16),
              ),
              child: Text(text, style: const TextStyle(fontSize: 16)),
            ))
                .toList(),
          ),
        ),
      ),
    );
  }
}

class _TextWrapFlowDelegate extends FlowDelegate {
  final List<String> texts;
  final TextStyle style;
  final EdgeInsets padding; // 内边距
  final EdgeInsets margin; // 外边距

  _TextWrapFlowDelegate({
    required this.texts,
    required this.style,
    this.padding = EdgeInsets.zero,
    this.margin = EdgeInsets.zero,
  });

  /// 测量文本宽高
  Size _measureText(String text) {
    final painter = TextPainter(
      text: TextSpan(text: text, style: style),
      maxLines: 1,
      textDirection: TextDirection.ltr,
    )..layout();
    // 加上 padding
    return Size(
      painter.width + padding.horizontal,
      painter.height + padding.vertical,
    );
  }

  @override
  void paintChildren(FlowPaintingContext context) {
    double x = 0;
    double y = 0;
    double rowHeight = 0;
    double maxWidth = context.size.width;

    for (int i = 0; i < context.childCount; i++) {
      final childSize = context.getChildSize(i)!;
      final nextX = x + childSize.width + margin.horizontal;

      if (nextX > maxWidth) {
        x = 0;
        y += rowHeight + margin.vertical;
        rowHeight = 0;
      }

      context.paintChild(
        i,
        transform: Matrix4.translationValues(x + margin.left, y + margin.top, 0),
      );

      x += childSize.width + margin.horizontal;
      rowHeight = rowHeight < childSize.height ? childSize.height : rowHeight;
    }
  }

  @override
  Size getSize(BoxConstraints constraints) {
    double maxWidth = constraints.maxWidth;
    double x = 0;
    double y = 0;
    double rowHeight = 0;

    for (var text in texts) {
      final size = _measureText(text);
      final nextX = x + size.width + margin.horizontal;

      if (nextX > maxWidth) {
        x = 0;
        y += rowHeight + margin.vertical;
        rowHeight = 0;
      }

      x += size.width + margin.horizontal;
      rowHeight = rowHeight < size.height ? size.height : rowHeight;
    }

    final totalHeight = y + rowHeight + margin.top + margin.bottom;
    return Size(maxWidth, totalHeight);
  }

  @override
  bool shouldRepaint(covariant _TextWrapFlowDelegate oldDelegate) {
    return oldDelegate.texts != texts ||
        oldDelegate.style != style ||
        oldDelegate.padding != padding ||
        oldDelegate.margin != margin;
  }
}
